/*
 * Copyright (c) 2023-2024 elsfs Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.elsfs.cloud.module.datasource.biz.manager;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import org.elsfs.cloud.common.core.utils.SpringContextHolder;
import org.elsfs.cloud.common.util.lang.EnumUtils;
import org.elsfs.cloud.common.util.lang.NamingCase;
import org.elsfs.cloud.common.util.lang.StringUtils;
import org.elsfs.cloud.module.datasource.biz.entity.GenGroup;
import org.elsfs.cloud.module.datasource.biz.entity.GenTable;
import org.elsfs.cloud.module.datasource.biz.entity.GenTableColumn;
import org.elsfs.cloud.module.datasource.biz.enums.BoolFillEnum;
import org.elsfs.cloud.module.datasource.biz.enums.CommonColumnFiledEnum;
import org.elsfs.cloud.module.datasource.biz.mapper.GeneratorMapper;
import org.elsfs.cloud.module.datasource.biz.properties.CodeGenProperties;
import org.elsfs.cloud.module.datasource.biz.repository.GenGroupRepository;
import org.elsfs.cloud.module.datasource.biz.repository.GenTableColumnRepository;
import org.elsfs.cloud.module.datasource.biz.repository.GenTableRepository;
import org.elsfs.cloud.module.datasource.biz.vo.GenTableVo;
import org.elsfs.cloud.module.dict.api.entity.GenDatasourceConf;
import org.elsfs.cloud.module.dict.api.enums.DsJdbcUrlEnum;
import org.elsfs.cloud.module.dict.api.repository.mapper.GenDatasourceConfMapper;
import org.elsfs.cloud.module.dict.api.support.DataSourceConstants;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 生成表管理
 *
 * @author zeng
 */
@Service
@RequiredArgsConstructor
@Import(CodeGenProperties.class)
public class GenTableManager {
  private final GenTableRepository genTableRepository;
  private final CodeGenProperties codeGenProperties;
  private final GenTableColumnRepository genTableColumnRepository;
  private final GenGroupRepository genGroupRepository;
  private final GenTableColumnManager genTableColumnManager;
  private final DataSource dataSource;

  /**
   * 同步表信息
   *
   * @param dsName 数据源
   * @param tableName 表名称
   */
  @Transactional(rollbackFor = Exception.class)
  public GenTableVo sync(String dsName, String tableName) {
    // 表配置删除
    genTableRepository.remove(
        Wrappers.<GenTable>lambdaQuery()
            .eq(GenTable::getDsName, dsName)
            .eq(GenTable::getTableName, tableName));
    // 字段配置删除
    genTableColumnRepository.remove(
        Wrappers.<GenTableColumn>lambdaQuery()
            .eq(GenTableColumn::getDsName, dsName)
            .eq(GenTableColumn::getTableName, tableName));
    return queryOrBuildTable(dsName, tableName);
  }

  /**
   * 修改表字段数据
   *
   * @param dsName 数据源
   * @param tableName 表名称
   * @param tableFieldList 字段列表
   */
  public boolean updateTableField(
      String dsName, String tableName, List<GenTableColumn> tableFieldList) {
    genTableColumnManager.updateTableField(dsName, tableName, tableFieldList);
    return true;
  }

  /**
   * 查询指定数据源下的所有表
   *
   * @param dsName 数据源名称
   * @return list
   */
  public List<GenTableVo> queryDsAllTable(String dsName) {
    GeneratorMapper mapper = getMapper(dsName);
    // 手动切换数据源
    DynamicDataSourceContextHolder.push(dsName);
    return mapper.queryTable();
  }

  /**
   * 查询指定数据源下的指定表下的所有字段
   *
   * @param dsName 数据源
   * @param tableName tableName
   * @return list
   */
  public List<GenTableColumn> queryColumn(String dsName, String tableName) {
    GeneratorMapper mapper = getMapper(dsName);
    return mapper.selectMapTableColumn(tableName, dsName);
  }

  /**
   * 分页查询表信息
   *
   * @param page 分页对象
   * @param table 查询条件
   * @return 表格列表分页结果
   */
  public IPage<GenTableVo> page(IPage<GenTableVo> page, GenTableVo table) {
    GeneratorMapper mapper = getMapper(table.getDsName());

    if (StringUtils.isBlank(table.getDsName())) {
      table.setDsName(DataSourceConstants.DS_MASTER);
    }
    // 手动切换数据源
    String dsName = DynamicDataSourceContextHolder.push(table.getDsName());

    return mapper.queryTable(page, table.getTableName(), dsName);
  }

  /**
   * 根据数据源名称和表名查询或构建表格
   *
   * @param dsName 数据源名称
   * @param tableName 表名
   * @return 查询到的表格信息
   */
  @Transactional(rollbackFor = Exception.class)
  public GenTableVo queryOrBuildTable(String dsName, String tableName) {
    GenTableVo vo = genTableRepository.getGenTableVoByDsNameAndTableName(dsName, tableName);
    // 如果 genTable 为空， 执行导入
    if (Objects.isNull(vo)) {
      vo = this.tableImport(dsName, tableName);
    }
    List<GenTableColumn> fieldList =
        genTableColumnRepository.list(
            Wrappers.<GenTableColumn>lambdaQuery()
                .eq(GenTableColumn::getDsName, dsName)
                .eq(GenTableColumn::getTableName, tableName)
                .orderByAsc(GenTableColumn::getSort));
    vo.setFieldList(fieldList);
    // 查询模板分组信息
    List<GenGroup> groupEntities = genGroupRepository.list();
    vo.setGroupList(groupEntities);
    return vo;
  }

  /**
   * 表导入
   *
   * @param dsName 数据源名称
   * @param tableName 表名
   * @return GenTableVo
   */
  private GenTableVo tableImport(String dsName, String tableName) {
    GeneratorMapper mapper = getMapper(dsName);
    // 手动切换数据源
    DynamicDataSourceContextHolder.push(dsName);

    // 从数据库获取表信息
    GenTableVo vo = mapper.queryTable(tableName, dsName);
    if (Objects.isNull(vo)) {
      // 查询表是否存在
      vo = new GenTableVo();
    }
    // 获取默认表配置信息 （）
    copyProperties(codeGenProperties, vo);
    vo.setTableName(tableName);
    vo.setDsName(dsName);
    vo.setClassName(NamingCase.toPascalCase(tableName));
    // 获取模块名称
    vo.setModuleName(StringUtils.subAfter(vo.getPackageName(), ".", true));
    //   获取功能名 sys_a_b sysAb
    vo.setFunctionName(NamingCase.toCamelCase(tableName));
    genTableRepository.save(vo);

    // 获取原生字段数据
    List<GenTableColumn> tableFieldList = mapper.selectMapTableColumn(tableName, dsName);

    for (GenTableColumn genTableColumn : tableFieldList) {
      genTableColumn.setTableName(tableName);
      genTableColumn.setDsName(dsName);
      genTableColumn.setAutoFill("DEFAULT");
      genTableColumn.setFormItem(BoolFillEnum.TRUE.getValue());
      genTableColumn.setGridItem(BoolFillEnum.TRUE.getValue());
      String fieldName = genTableColumn.getFieldName();
      // 审计字段处理
      if (EnumUtils.contains(CommonColumnFiledEnum.class, fieldName)) {
        CommonColumnFiledEnum commonColumnFiledEnum = CommonColumnFiledEnum.valueOf(fieldName);
        genTableColumn.setFormItem(commonColumnFiledEnum.getFormItem());
        genTableColumn.setGridItem(commonColumnFiledEnum.getGridItem());
        genTableColumn.setAutoFill(commonColumnFiledEnum.getAutoFill());
        genTableColumn.setSort(commonColumnFiledEnum.getSort());
      }
    }
    // 初始化字段数据
    genTableColumnManager.initFieldList(tableFieldList);
    // 保存列数据
    genTableColumnRepository.saveOrUpdateBatch(tableFieldList);
    vo.setFieldList(tableFieldList);
    return vo;
  }

  private void copyProperties(CodeGenProperties codeGenProperties, GenTableVo vo) {
    vo.setPackageName(codeGenProperties.getPackageName());
    vo.setVersion(codeGenProperties.getVersion());
    vo.setBackendPath(codeGenProperties.getBackendPath());
    vo.setFrontendPath(codeGenProperties.getFrontendPath());
    vo.setAuthor(codeGenProperties.getAuthor());
    vo.setEmail(codeGenProperties.getEmail());
    vo.setFormLayout(codeGenProperties.getFormLayout());
    vo.setModuleName(codeGenProperties.getModuleName());
    vo.setGeneratorType(codeGenProperties.getGeneratorType());
  }

  /**
   * 获取数据源对应方言的mapper
   *
   * @param dsName 数据源名称
   * @return GeneratorMapper
   */
  public static GeneratorMapper getMapper(String dsName) {
    // 获取目标数据源数据库类型
    GenDatasourceConfMapper datasourceConfMapper =
        SpringContextHolder.getBean(GenDatasourceConfMapper.class);
    GenDatasourceConf datasourceConf =
        datasourceConfMapper.selectOne(
            Wrappers.<GenDatasourceConf>lambdaQuery().eq(GenDatasourceConf::getName, dsName));
    // 默认MYSQL 数据源
    String dbConfType =
        datasourceConf == null ? DsJdbcUrlEnum.MYSQL.getDbName() : datasourceConf.getDsType();

    // 获取全部数据实现
    ApplicationContext context = SpringContextHolder.getApplicationContext();
    Map<String, GeneratorMapper> beansOfType = context.getBeansOfType(GeneratorMapper.class);
    // 根据数据类型选择mapper
    for (String key : beansOfType.keySet()) {
      if (StringUtils.containsIgnoreCase(key, dbConfType)) {
        return beansOfType.get(key);
      }
    }

    throw new IllegalArgumentException("dsName 不合法: " + dsName);
  }
}
